#ifndef xrtcp_util_hpp
#define xrtcp_util_hpp

#include <stdio.h>
#include <stdint.h>
#include <stddef.h> // size_t, ptrdiff_t
#include "xcutil.h"
#include "rtcp_utility.h"
#include "rtp/rtcp/transport_feedback.hpp"

using namespace webrtc::RTCPUtility;

typedef struct rtcp_parser_st * rtcp_parser_t;

rtcp_parser_t rtcp_parser_create();
void rtcp_parser_delete(rtcp_parser_t parser);
int rtcp_parse_first(rtcp_parser_t parser, const uint8_t * data, int length );
int rtcp_parse_next_item(rtcp_parser_t  parser);
int rtcp_parse_next_packet(rtcp_parser_t  parser);
const RtcpCommonHeader * rtcp_get_header(rtcp_parser_t parser);
const RTCPPacket * rtcp_get_body(rtcp_parser_t parser);
TransportFeedback* rtcp_get_transport_feedback(rtcp_parser_t parser);




static inline
int make_rtcp_sr_info(uint8_t * buf, uint32_t sender_ssrc, uint32_t ntp_msw, uint32_t ntp_lsw, uint32_t rtp_ts, uint32_t sent_pkts, uint32_t sent_bytes){
    // http://www.networksorcery.com/enp/rfc/rfc3550.txt
    // 6.4.1 SR: Sender Report RTCP Packet
    //        0                   1                   2                   3
    //        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //header |V=2|P|    RC   |   PT=SR=200   |             length            |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                         SSRC of sender                        |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //sender |              NTP timestamp, most significant word             |
    //info   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |             NTP timestamp, least significant word             |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                         RTP timestamp                         |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                     sender's packet count                     |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                      sender's octet count                     |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //report |                 SSRC_1 (SSRC of first source)                 |
    //block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  1    | fraction lost |       cumulative number of packets lost       |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |           extended highest sequence number received           |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                      interarrival jitter                      |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                         last SR (LSR)                         |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                   delay since last SR (DLSR)                  |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //report |                 SSRC_2 (SSRC of second source)                |
    //block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  2    :                               ...                             :
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //       |                  profile-specific extensions                  |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    const uint8_t v = 2;
    const uint8_t p = 0;
    const uint8_t rc = 0;
    const uint8_t pt = 200;
    const uint16_t pkt_words = 6;
    
    buf[0] = (v<<6) | (p << 5) | (rc << 0);
    buf[1] = pt;
    be_set_u16(pkt_words, buf+2);
    be_set_u32(sender_ssrc, buf+4);
    be_set_u32(ntp_msw, buf+8);
    be_set_u32(ntp_lsw, buf+12);
    be_set_u32(rtp_ts, buf+16);
    be_set_u32(sent_pkts, buf+20);
    be_set_u32(sent_bytes, buf+24);
    return 28;
}

static inline
int make_rtcp_rr_info(uint8_t * buf, uint32_t sender_ssrc, uint8_t blocks_count){
    // http://www.networksorcery.com/enp/rfc/rfc3550.txt
    // 6.4.2 RR: Receiver Report RTCP Packet
    //        0                   1                   2                   3
    //        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //header |V=2|P|    RC   |   PT=RR=201   |             length            |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                     SSRC of packet sender                     |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //report |                 SSRC_1 (SSRC of first source)                 |
    //block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  1    | fraction lost |       cumulative number of packets lost       |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |           extended highest sequence number received           |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                      interarrival jitter                      |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                         last SR (LSR)                         |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                   delay since last SR (DLSR)                  |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //report |                 SSRC_2 (SSRC of second source)                |
    //block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  2    :                               ...                             :
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //       |                  profile-specific extensions                  |
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    
    // An empty RR packet (RC = 0) is put at the head of a compound RTCP packet when there is no data transmission or reception to report.
    
    const uint8_t v = 2;
    const uint8_t p = 0;
    const uint8_t rc = blocks_count;
    const uint8_t pt = 201;
    const uint16_t pkt_words = 1 + blocks_count * 6;
    
    buf[0] = (v<<6) | (p << 5) | (rc << 0);
    buf[1] = pt;
    be_set_u16(pkt_words, buf+2);
    be_set_u32(sender_ssrc, buf+4);
    
    return 8;
    
}

static inline
int make_rtcp_report_block(uint8_t* buf, uint32_t ssrc, int lost_frac, uint32_t lost_cumulative,
                           uint32_t extended_highest_seq, uint32_t inter_arrival_jitter,
                           uint32_t lsr, uint32_t dlsr) {
    uint8_t* b = buf;
    be_set_u32(ssrc, b); b += 4;
    *b = lost_frac; b += 1;
    be_set_u24(lost_cumulative, b); b += 3;
    be_set_u32(extended_highest_seq, b); b += 4;
    be_set_u32(inter_arrival_jitter, b); b += 4;
    be_set_u32(lsr, b); b += 4;
    be_set_u32(dlsr, b); b += 4;

    return int(b - buf);
}

static inline
int make_rtcp_sdes(uint8_t * buf, uint32_t sender_ssrc, const char *cname, int cname_len){
    // http://www.networksorcery.com/enp/rfc/rfc3550.txt
    //6.5 SDES: Source Description RTCP Packet
    //        0                   1                   2                   3
    //        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //header |V=2|P|    SC   |  PT=SDES=202  |             length            |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //chunk  |                          SSRC/CSRC_1                          |
    //  1    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                           SDES items                          |
    //       |                              ...                              |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    //chunk  |                          SSRC/CSRC_2                          |
    //  2    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       |                           SDES items                          |
    //       |                              ...                              |
    //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    
    //    0                   1                   2                   3
    //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |    CNAME=1    |     length    | user and domain name        ...
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    
    
    const uint8_t v = 2;
    const uint8_t p = 0;
    const uint8_t sc = 1;
    const uint8_t pt = 202;
    int plen = 8;
    plen += cname_len + 3;
    plen = (plen + 3) & 0xFFFC;
    
    // uint16_t pkt_words = 1;
    // pkt_words += ((2+cname_len)/4);
    // if((2+cname_len)%4){
    //     buf[pkt_words*4+1] = 0;
    //     buf[pkt_words*4+2] = 0;
    //     buf[pkt_words*4+3] = 0;
    //     pkt_words++;
    // }
    
    buf[0] = (v<<6) | (p << 5) | (sc << 0);
    buf[1] = pt;
    be_set_u16((plen/4-1), buf+2);
    be_set_u32(sender_ssrc, buf+4);
    buf[8] = 1;
    buf[9] = cname_len;
    memcpy(buf+10, cname, cname_len);
    memset(buf+10+cname_len, 0, plen-cname_len-10);
    
    return plen;
}

static inline
int make_rtcp_remb(uint8_t * buf, uint32_t sender_ssrc, uint32_t media_ssrc, uint32_t media_ssrc2, uint32_t remb_bitrate){
    // https://tools.ietf.org/id/draft-alvestrand-rmcat-remb-03.html
    // 0                   1                   2                   3
    // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|V=2|P| FMT=15  |   PT=206      |             length            |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|                  SSRC of packet sender                        |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|                  SSRC of media source                         |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  Unique identifier 'R' 'E' 'M' 'B'                            |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  Num SSRC     | BR Exp    |  BR Mantissa                      |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|   SSRC feedback                                               |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  ...                                                          |
    
    /* bitrate --> brexp/brmantissa */
    uint8_t b = 0;
    uint8_t newbrexp = 0;
    uint32_t newbrmantissa = 0;
    for(b=0; b<64; b++) {
        if(remb_bitrate <= ((uint64_t) 0x3FFFF << b)) {
            newbrexp = b;
            break;
        }
    }
    newbrmantissa = remb_bitrate >> b;
    
    const uint8_t v = 2;
    const uint8_t p = 0;
    const uint8_t fmt = 15;
    const uint8_t pt = 206;
    uint16_t pkt_words = 5;
    if (media_ssrc2) {
        pkt_words += 1;
    }
    
    buf[0] = (v<<6) | (p << 5) | (fmt << 0);
    buf[1] = pt;
    be_set_u16(pkt_words, buf+2);
    be_set_u32(sender_ssrc, buf+4);
    be_set_u32(0, buf+8);
    buf[12+0] = 'R';
    buf[12+1] = 'E';
    buf[12+2] = 'M';
    buf[12+3] = 'B';
    
    buf[16+0] = 1; // Num SSRC
    if (media_ssrc2) {
        buf[16+0] = 2;
    }
    buf[16+1] = (uint8_t)((newbrexp << 2) + ((newbrmantissa >> 16) & 0x03));
    buf[16+2] = (uint8_t)(newbrmantissa >> 8);
    buf[16+3] = (uint8_t)(newbrmantissa);
    be_set_u32(media_ssrc, buf+20);
    if (media_ssrc2) {
        be_set_u32(media_ssrc2, buf+24);
    }

    
    return 4+pkt_words*4;
    
}


static inline
int make_rtcp_esmb(uint8_t * buf, uint32_t sender_ssrc, uint32_t media_ssrc, uint32_t bitrate_max){
    // ESMB stands for Extended Suggested Max Bitrate, modified from REMB
    // 0                   1                   2                   3
    // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|V=2|P| FMT=15  |   PT=206      |             length            |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|                  SSRC of packet sender                        |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|                  SSRC of media source                         |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  Unique identifier 'E' 'S' 'M' 'B'                            |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  SSRC feebback                                                |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  Bitrate Max                                                  |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  Reserved 0                                                   |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  Reserved 1                                                   |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //|  Reserved 2                                                   |
    //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    const uint8_t v = 2;
    const uint8_t p = 0;
    const uint8_t fmt = 15;
    const uint8_t pt = 206;
    uint16_t pkt_words = 8;

    buf[0] = (v<<6) | (p << 5) | (fmt << 0);
    buf[1] = pt;
    be_set_u16(pkt_words, buf+2);
    be_set_u32(sender_ssrc, buf+4);
    be_set_u32(0, buf+8);
    buf[12+0] = 'E';
    buf[12+1] = 'S';
    buf[12+2] = 'M';
    buf[12+3] = 'B';

    be_set_u32(media_ssrc, buf+16);
    be_set_u32(bitrate_max, buf+20);
    be_set_u32(0, buf+24); // reserved 0
    be_set_u32(0, buf+28); // reserved 1
    be_set_u32(0, buf+32); // reserved 2

    return 4+pkt_words*4;
}

static inline
int make_rtcp_pli(uint8_t * buf, uint32_t sender_ssrc, uint32_t media_ssrc){
    //    https://tools.ietf.org/html/rfc4585
    //    6.1.   Common Packet Format for Feedback Messages
    //    0                   1                   2                   3
    //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |V=2|P|   FMT   |       PT      |          length               |
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |                  SSRC of packet sender                        |
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |                  SSRC of media source                         |
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   :            Feedback Control Information (FCI)                 :
    //   :                                                               :
    //
    //            Name   | Value | Brief Description
    //         ----------+-------+------------------------------------
    //            RTPFB  |  205  | Transport layer FB message
    //            PSFB   |  206  | Payload-specific FB message
    //
    //   6.3.1.  Picture Loss Indication (PLI)
    //    The PLI FB message is identified by PT=PSFB and FMT=1.
    //   6.3.1.2.  Message Format
    //   PLI does not require parameters.  Therefore, the length field MUST be
    //   2, and there MUST NOT be any Feedback Control Information.
    
    const uint8_t v = 2;
    const uint8_t p = 0;
    const uint8_t fmt = 1;
    const uint8_t pt = 206;
    const uint16_t pkt_words = 2;
    
    buf[0] = (v<<6) | (p << 5) | (fmt << 0);
    buf[1] = pt;
    be_set_u16(pkt_words, buf+2);
    be_set_u32(sender_ssrc, buf+4);
    be_set_u32(media_ssrc, buf+8);
    return 12;
    
}

static inline
int make_rtcp_nack(uint8_t * buf, uint32_t sender_ssrc, uint32_t media_ssrc, uint16_t pid, uint16_t blp){
    //    https://tools.ietf.org/html/rfc4585
    //    6.1.   Common Packet Format for Feedback Messages
    //    0                   1                   2                   3
    //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |V=2|P|   FMT   |       PT      |          length               |
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |                  SSRC of packet sender                        |
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |                  SSRC of media source                         |
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   :            Feedback Control Information (FCI)                 :
    //   :                                                               :
    //
    //            Name   | Value | Brief Description
    //         ----------+-------+------------------------------------
    //            RTPFB  |  205  | Transport layer FB message
    //            PSFB   |  206  | Payload-specific FB message
    //6.2.1.  Generic NACK
    //
    //   The Generic NACK message is identified by PT=RTPFB and FMT=1.
    //    0                   1                   2                   3
    //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //   |            PID                |             BLP               |
    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    
    
    const uint8_t v = 2;
    const uint8_t p = 0;
    const uint8_t fmt = 1;
    const uint8_t pt = 205;
    const uint16_t pkt_words = 3;
    
    buf[0] = (v<<6) | (p << 5) | (fmt << 0);
    buf[1] = pt;
    be_set_u16(pkt_words, buf+2);
    be_set_u32(sender_ssrc, buf+4);
    be_set_u32(media_ssrc, buf+8);
    be_set_u16(pid, buf+12);
    be_set_u16(blp, buf+14);
    
    return 16;
    
}

static inline
int make_rtcp_CNSL(uint8_t * buf, uint32_t sender_ssrc, uint8_t l){
    //    https://tools.ietf.org/html/rfc4585
    // 6.7 APP: Application-Defined RTCP Packet
    // 0                   1                   2                   3
    // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |V=2|P|    0    |   PT=APP=204  |             length            |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |                           SSRC/CSRC                           |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |                   name (ASCII)='CNSL'                         |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |                         reserved                          | L |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //
    // L字段制定了密级
    // L=0：公开
    // L=1：内部
    // L=2：秘密级
    // L=3：机密级
    const uint8_t v = 2;
    const uint8_t p = 0;
    // const uint8_t fmt = 0;
    const uint8_t pt = 204;
    const uint16_t pkt_words = 3;
    char name[5] = "CNSL";
    
    buf[0] = (v<<6) | (p << 5) ;
    buf[1] = pt;
    be_set_u16(pkt_words, buf+2);
    be_set_u32(sender_ssrc, buf+4);
    memcpy(buf+8, name, 4);
    be_set_u32((int)l, buf+12);
    
    return 16;
}
#endif /* xrtcp_util_hpp */

















#if 0


#ifndef xrtcp_util_hpp
#define xrtcp_util_hpp

#include <stdio.h>
#include <stdint.h>
#include <stddef.h> // size_t, ptrdiff_t

//#include "webrtc/base/scoped_ptr.h"
//#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
//#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
//#include "webrtc/typedefs.h"



//
// rtp_rtcp_config.h ==>
//

//enum { NACK_BYTECOUNT_SIZE = 60 };  // size of our NACK history
//// A sanity for the NACK list parsing at the send-side.
//enum { kSendSideNackListSizeSanity = 20000 };
//enum { kDefaultMaxReorderingThreshold = 50 };  // In sequence numbers.
//enum { kRtcpMaxNackFields = 253 };
//
//enum { RTCP_INTERVAL_VIDEO_MS = 1000 };
//enum { RTCP_INTERVAL_AUDIO_MS = 5000 };
//enum { RTCP_SEND_BEFORE_KEY_FRAME_MS = 100 };
//enum { RTCP_MAX_REPORT_BLOCKS = 31 };  // RFC 3550 page 37
//enum { RTCP_MIN_FRAME_LENGTH_MS = 17 };
enum {
    kRtcpAppCode_DATA_SIZE = 32 * 4
};  // multiple of 4, this is not a limitation of the size
enum { RTCP_RPSI_DATA_SIZE = 30 };
//enum { RTCP_NUMBER_OF_SR = 60 };
//
//enum { MAX_NUMBER_OF_TEMPORAL_ID = 8 };              // RFC
//enum { MAX_NUMBER_OF_DEPENDENCY_QUALITY_ID = 128 };  // RFC
enum { MAX_NUMBER_OF_REMB_FEEDBACK_SSRCS = 255 };
//
//enum { BW_HISTORY_SIZE = 35 };
//
//#define MIN_AUDIO_BW_MANAGEMENT_BITRATE 6
//#define MIN_VIDEO_BW_MANAGEMENT_BITRATE 30
//
//enum { DTMF_OUTBAND_MAX = 20 };
//
//enum { RTP_MAX_BURST_SLEEP_TIME = 500 };
//enum { RTP_AUDIO_LEVEL_UNIQUE_ID = 0xbede };
//enum { RTP_MAX_PACKETS_PER_FRAME = 512 };  // must be multiple of 32

//
// rtp_rtcp_config.h <==
//








// rtp_rtcp_defines.h ==>

#define RTCP_CNAME_SIZE 256    // RFC 3550 page 44, including null termination
//#define IP_PACKET_SIZE 1500    // we assume ethernet
//#define MAX_NUMBER_OF_PARALLEL_TELEPHONE_EVENTS 10
//#define TIMEOUT_SEI_MESSAGES_MS 30000   // in milliseconds


// rtp_rtcp_defines.h <==



// CNAME
struct RTCPCnameInformation {
    char name[RTCP_CNAME_SIZE];
};
struct RTCPPacketRR {
    uint32_t SenderSSRC;
    uint8_t NumberOfReportBlocks;
};
struct RTCPPacketSR {
    uint32_t SenderSSRC;
    uint8_t NumberOfReportBlocks;
    
    // sender info
    uint32_t NTPMostSignificant;
    uint32_t NTPLeastSignificant;
    uint32_t RTPTimestamp;
    uint32_t SenderPacketCount;
    uint32_t SenderOctetCount;
};
struct RTCPPacketReportBlockItem {
    // report block
    uint32_t SSRC;
    uint8_t FractionLost;
    uint32_t CumulativeNumOfPacketsLost;
    uint32_t ExtendedHighestSequenceNumber;
    uint32_t Jitter;
    uint32_t LastSR;
    uint32_t DelayLastSR;
};
struct RTCPPacketSDESCName {
    // RFC3550
    uint32_t SenderSSRC;
    char CName[RTCP_CNAME_SIZE];
};

struct RTCPPacketExtendedJitterReportItem {
    // RFC 5450
    uint32_t Jitter;
};

struct RTCPPacketBYE {
    uint32_t SenderSSRC;
};
struct RTCPPacketXR {
    // RFC 3611
    uint32_t OriginatorSSRC;
};
struct RTCPPacketXRReceiverReferenceTimeItem {
    // RFC 3611 4.4
    uint32_t NTPMostSignificant;
    uint32_t NTPLeastSignificant;
};
struct RTCPPacketXRDLRRReportBlockItem {
    // RFC 3611 4.5
    uint32_t SSRC;
    uint32_t LastRR;
    uint32_t DelayLastRR;
};
struct RTCPPacketXRVOIPMetricItem {
    // RFC 3611 4.7
    uint32_t SSRC;
    uint8_t lossRate;
    uint8_t discardRate;
    uint8_t burstDensity;
    uint8_t gapDensity;
    uint16_t burstDuration;
    uint16_t gapDuration;
    uint16_t roundTripDelay;
    uint16_t endSystemDelay;
    uint8_t signalLevel;
    uint8_t noiseLevel;
    uint8_t RERL;
    uint8_t Gmin;
    uint8_t Rfactor;
    uint8_t extRfactor;
    uint8_t MOSLQ;
    uint8_t MOSCQ;
    uint8_t RXconfig;
    uint16_t JBnominal;
    uint16_t JBmax;
    uint16_t JBabsMax;
};

struct RTCPPacketRTPFBNACK {
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;
};
struct RTCPPacketRTPFBNACKItem {
    // RFC4585
    uint16_t PacketID;
    uint16_t BitMask;
};

struct RTCPPacketRTPFBTMMBR {
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;  // zero!
};
struct RTCPPacketRTPFBTMMBRItem {
    // RFC5104
    uint32_t SSRC;
    uint32_t MaxTotalMediaBitRate;  // In Kbit/s
    uint32_t MeasuredOverhead;
};

struct RTCPPacketRTPFBTMMBN {
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;  // zero!
};
struct RTCPPacketRTPFBTMMBNItem {
    // RFC5104
    uint32_t SSRC;  // "Owner"
    uint32_t MaxTotalMediaBitRate;
    uint32_t MeasuredOverhead;
};

struct RTCPPacketPSFBFIR {
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;  // zero!
};
struct RTCPPacketPSFBFIRItem {
    // RFC5104
    uint32_t SSRC;
    uint8_t CommandSequenceNumber;
};

struct RTCPPacketPSFBPLI {
    // RFC4585
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;
};

struct RTCPPacketPSFBSLI {
    // RFC4585
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;
};
struct RTCPPacketPSFBSLIItem {
    // RFC4585
    uint16_t FirstMB;
    uint16_t NumberOfMB;
    uint8_t PictureId;
};
struct RTCPPacketPSFBRPSI {
    // RFC4585
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;
    uint8_t PayloadType;
    uint16_t NumberOfValidBits;
    uint8_t NativeBitString[RTCP_RPSI_DATA_SIZE];
};
struct RTCPPacketPSFBAPP {
    uint32_t SenderSSRC;
    uint32_t MediaSSRC;
};
struct RTCPPacketPSFBREMBItem {
    uint32_t BitRate;
    uint8_t NumberOfSSRCs;
    uint32_t SSRCs[MAX_NUMBER_OF_REMB_FEEDBACK_SSRCS];
};
// generic name APP
struct RTCPPacketAPP {
    uint8_t SubType;
    uint32_t Name;
    uint8_t Data[kRtcpAppCode_DATA_SIZE];
    uint16_t Size;
};

union RTCPPacket {
    RTCPPacketRR RR;
    RTCPPacketSR SR;
    RTCPPacketReportBlockItem ReportBlockItem;
    
    RTCPPacketSDESCName CName;
    RTCPPacketBYE BYE;
    
    RTCPPacketExtendedJitterReportItem ExtendedJitterReportItem;
    
    RTCPPacketRTPFBNACK NACK;
    RTCPPacketRTPFBNACKItem NACKItem;
    
    RTCPPacketPSFBPLI PLI;
    RTCPPacketPSFBSLI SLI;
    RTCPPacketPSFBSLIItem SLIItem;
    RTCPPacketPSFBRPSI RPSI;
    RTCPPacketPSFBAPP PSFBAPP;
    RTCPPacketPSFBREMBItem REMBItem;
    
    RTCPPacketRTPFBTMMBR TMMBR;
    RTCPPacketRTPFBTMMBRItem TMMBRItem;
    RTCPPacketRTPFBTMMBN TMMBN;
    RTCPPacketRTPFBTMMBNItem TMMBNItem;
    RTCPPacketPSFBFIR FIR;
    RTCPPacketPSFBFIRItem FIRItem;
    
    RTCPPacketXR XR;
    RTCPPacketXRReceiverReferenceTimeItem XRReceiverReferenceTimeItem;
    RTCPPacketXRDLRRReportBlockItem XRDLRRReportBlockItem;
    RTCPPacketXRVOIPMetricItem XRVOIPMetricItem;
    
    RTCPPacketAPP APP;
};

#define  kHeaderSizeBytes 4
struct RtcpCommonHeader {
    uint8_t version;
    uint8_t count_or_format;
    uint8_t packet_type;
    uint32_t payload_size_bytes;
    uint8_t padding_bytes;
};

enum RTCPPacketTypes {
    kInvalid,
    
    // RFC3550
    kRr,
    kSr,
    kReportBlockItem,
    
    kSdes,
    kSdesChunk,
    kBye,
    
    // RFC5450
    kExtendedIj,
    kExtendedIjItem,
    
    // RFC4585
    kRtpfbNack,
    kRtpfbNackItem,
    
    kPsfbPli,
    kPsfbRpsi,
    kPsfbSli,
    kPsfbSliItem,
    kPsfbApp,
    kPsfbRemb,
    kPsfbRembItem,
    
    // RFC5104
    kRtpfbTmmbr,
    kRtpfbTmmbrItem,
    kRtpfbTmmbn,
    kRtpfbTmmbnItem,
    kPsfbFir,
    kPsfbFirItem,
    
    // draft-perkins-avt-rapid-rtp-sync
    kRtpfbSrReq,
    
    // RFC 3611
    kXrHeader,
    kXrReceiverReferenceTime,
    kXrDlrrReportBlock,
    kXrDlrrReportBlockItem,
    kXrVoipMetric,
    
    kApp,
    kAppItem,
    
    // draft-holmer-rmcat-transport-wide-cc-extensions
    kTransportFeedback,
};


struct RtcpParser {
    RtcpCommonHeader header;
    RTCPPacket _packet;

// private field
    int _state;
//    int validPacket_;
//    int packetType_;
    
    const uint8_t*  _ptrRTCPDataBegin;
    const uint8_t*  _ptrRTCPDataEnd;
    uint8_t _numberOfBlocks;
    
    
    bool _validPacket;
    const uint8_t* _ptrRTCPData;
    const uint8_t* _ptrRTCPBlockEnd;
    
    size_t num_skipped_blocks_;
    
    RTCPPacketTypes _packetType;
    
    
    
    
//    const uint8_t * pkt_;
//    int remain_len_;
    
};



int rtcp_parse_first(const uint8_t * data, int length, RtcpParser * parser );
int rtcp_parse_next(RtcpParser * parser);
#define rtcp_current_header(x) (&(x)->heaer)
#define rtcp_current_body(x) (&(x)->body)

#endif /* xrtcp_util_hpp */




#endif

